/*
 * File:   ServerStorageProtocol.cpp
 * Author: wilq
 *
 * Created on June 13, 2012, 7:40 PM
 */
#include "ServerStorageProtocol.h"
#include "ConnectionManager.h"

ServerStorageProtocol::ServerStorageProtocol(socket_ptr s) : BaseServerProtocol(s) {
    FUNCTION_TRACK
	this->connectedStorageId = 0;
	AddHandler<ServerStorageProtocol > ((int32_t) CSNetworkLib::PACKET_SERVER_AuthStorageReq, & ServerStorageProtocol::OnStorageAuthorization);
}

ServerStorageProtocol::~ServerStorageProtocol()
{
    FUNCTION_TRACK
	if (this->connectedStorageId != 0)
	{
        ConnectionManager::getInstance().CloseHandlesStorage(this);
		ConnectionManager::getInstance().RemoveStorage(this->connectedStorageId);
	}
	this->connectedStorageId = 0;
}


THANDLE ServerStorageProtocol::FileOpen(const std::string &link, const std::string &options)
{
    FUNCTION_TRACK
	if (link.empty() || options.empty())
		return 0;
	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileOpen_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(link.c_str());
	request.Push_String(options.c_str());

	if (!SendPacketWait(request, response))
		return 0;

	uint32_t ret = 0;
	response.Get_U32(0, ret);
	return ret;
}

THANDLE ServerStorageProtocol::FileOpen(const std::string &parentlink, const std::string &name, const std::string &options)
{
    FUNCTION_TRACK
	if (parentlink.empty() || options.empty()|| name.empty())
		return 0;
	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileOpen_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(parentlink.c_str());
	request.Push_String(options.c_str());
	request.Push_String(name.c_str());

	if (!SendPacketWait(request, response))
		return 0;

	uint32_t ret = 0;
	response.Get_U32(0, ret);
	return ret;
}

bool ServerStorageProtocol::FileClose(THANDLE file)
{
    FUNCTION_TRACK
	if (0 == file)
		return true;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileClose_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_U32(file);

	if (!SendPacketWait(request, response))
		return false;

	uint32_t ret = 0;
	response.Get_U32(0, ret);
	return ((0 == ret) || (1 == ret));
}

bool ServerStorageProtocol::FileInfo(THANDLE file, uint8_t infoType /*0 - size, 1 - timestamp, 2 - position*/, uint64_t &outInfo)
{
    FUNCTION_TRACK
	if (0 == file)
		return false;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileInfo_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_U32(file);
    request.Push_U8(infoType);
	if (!SendPacketWait(request, response))
		return false;

	if (!response.Get_U64(0, outInfo)) return false;
	return true;
}

bool ServerStorageProtocol::FileSeek(THANDLE file, int64_t position /*-1 for end*/)
{
    FUNCTION_TRACK
	if (0 == file)
		return false;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileSeek_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_U32(file);
	request.Push_S64(position);

	if (!SendPacketWait(request, response))
		return false;

	bool ret = false;
	response.Get_Bool(0, ret);
	return ret;
}

bool ServerStorageProtocol::FileEof(THANDLE file)
{
    FUNCTION_TRACK
	if (0 == file)
		return false;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileEof_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_U32(file);

	if (!SendPacketWait(request, response))
		return false;

	bool ret = true;
	response.Get_Bool(0, ret);
	return ret;
}

int32_t	ServerStorageProtocol::FileWrite(THANDLE file, uint32_t	size, const uint8_t *data)
{
    FUNCTION_TRACK
	if ((0 == file) || (NULL == data))
		return -2;

	if (0 == size)
		return 0;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileWrite_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_U32(file);
	request.Push_Data(data, size);

	if (!SendPacketWait(request, response))
		return -3;

	int32_t ret = 0;
	response.Get_S32(0, ret);
	return ret;
}

int32_t	ServerStorageProtocol::FileRead(THANDLE file, uint32_t size, uint8_t *data)
{
    FUNCTION_TRACK
	if ((0 == file) || (NULL == data))
		return -2;

	if (0 == size)
		return 0;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileRead_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_U32(file);
	request.Push_U32(size);

	if (!SendPacketWait(request, response))
		return -3;

	int32_t ret = 0;
	response.Get_S32(0, ret);

	if (ret>0)
	{
		if (!response.Get_Data(1, data, ret))
		{
			return -4;
		}
	}
	return ret;
}

int16_t	ServerStorageProtocol::FileDelete(const std::string &link)
{
    FUNCTION_TRACK
	if (link.empty())
		return -2;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileDelete_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(link.c_str());

	if (!SendPacketWait(request, response))
		return -3;

	int16_t ret = 0;
	response.Get_S16(0, ret);
	return ret;
}

int16_t	ServerStorageProtocol::FileMove(const std::string &link, const std::string &destinationFolderLink, const std::string &newFileName, bool force)
{
    FUNCTION_TRACK
	if (link.empty())
		return -2;
	if (destinationFolderLink.empty() && newFileName.empty())
		return -2;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileMove_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(link.c_str());
	request.Push_String(destinationFolderLink.c_str());
	request.Push_String(newFileName.c_str());
	request.Push_Bool(force);

	if (!SendPacketWait(request, response))
		return -3;

	int16_t ret = 0;
	response.Get_S16(0, ret);
	return ret;
}

int16_t	ServerStorageProtocol::FileCopy(const std::string &link, const std::string &destinationFolderLink, const std::string &newFileName, bool force)
{
    FUNCTION_TRACK
	if (link.empty())
		return -2;
	if (destinationFolderLink.empty() && newFileName.empty())
		return -2;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFileCopy_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(link.c_str());
	request.Push_String(destinationFolderLink.c_str());
	request.Push_String(newFileName.c_str());
	request.Push_Bool(force);

	if (!SendPacketWait(request, response))
		return -3;

	int16_t ret = 0;
	response.Get_S16(0, ret);
	return ret;
}

EType ServerStorageProtocol::FolderSync(const std::string &link, bool recursive)
{
    FUNCTION_TRACK
	if (link.empty())
		return ETYPE_ERROR;
	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFolderSync_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(link.c_str());
	request.Push_Bool(recursive);
	if (!SendPacketWait(request, response, 10*60*1000))
		return ETYPE_ERROR;
	uint8_t ret = 0;
	response.Get_U8(0, ret);
	return (EType)ret;
}

bool ServerStorageProtocol::FolderCreate(const std::string &link, const std::string &folderName)
{
    FUNCTION_TRACK
	if (link.empty() || folderName.empty())
		return -2;
	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFolderCreate_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(link.c_str());
	request.Push_String(folderName.c_str());

	if (!SendPacketWait(request, response))
		return 0;

	bool ret = false;
	response.Get_Bool(0, ret);
	return ret;
}

int16_t	ServerStorageProtocol::FolderMove(const std::string &link, const std::string &destinationFolderLink, const std::string &newFolderName, bool force)
{
    FUNCTION_TRACK
	if (link.empty())
		return -2;
	if (destinationFolderLink.empty() && newFolderName.empty())
		return -2;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFolderMove_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(link.c_str());
	request.Push_String(destinationFolderLink.c_str());
	request.Push_String(newFolderName.c_str());
	request.Push_Bool(force);

	if (!SendPacketWait(request, response))
		return -3;

	int16_t ret = 0;
	response.Get_S16(0, ret);
	return ret;
}

int16_t	ServerStorageProtocol::FolderCopy(const std::string &link, const std::string &destinationFolderLink, const std::string &newFolderName, bool force )
{
    FUNCTION_TRACK
	if (link.empty())
		return -2;
	if (destinationFolderLink.empty() && newFolderName.empty())
		return -2;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFolderCopy_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(link.c_str());
	request.Push_String(destinationFolderLink.c_str());
	request.Push_String(newFolderName.c_str());
	request.Push_Bool(force);

	if (!SendPacketWait(request, response))
		return -3;

	int16_t ret = 0;
	response.Get_S16(0, ret);
	return ret;
}

int16_t	ServerStorageProtocol::FolderDelete(const std::string &link)
{
    FUNCTION_TRACK
	if (link.empty())
		return -2;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnFolderDelete_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);

	request.Push_String(link.c_str());

	if (!SendPacketWait(request, response))
		return -3;

	int16_t ret = 0;
	response.Get_S16(0, ret);
	return ret;
}

EType ServerStorageProtocol::GetInfo(const std::string &link, std::string *out_link, std::string *out_name)
{
    FUNCTION_TRACK
	if (link.empty())
		return ETYPE_ERROR;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnGetType_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);
	request.Push_Bool(out_link!=NULL || out_name!=NULL);
	request.Push_String(link.c_str());

	if (!SendPacketWait(request, response))
		return ETYPE_ERROR;

	uint8_t ret = 0;
	response.Get_U8(0, ret);
	if (out_link!=NULL)
		*out_link = response.GetString(1);
	if (out_name!=NULL)
		*out_name = response.GetString(2);
	return (EType)ret;
}

EType ServerStorageProtocol::GetInfo(const std::string &parentLink, const std::string &name, std::string *out_link, std::string *out_name)
{
    FUNCTION_TRACK
	if (parentLink.empty() || name.empty())
		return ETYPE_ERROR;

	CSNetworkLib::NetworkPacket request(CSNetworkLib::PACKET_STORAGE_OnGetType_Req);
	CSNetworkLib::NetworkPacket response;
	request.SetWaitingForResponse(true);
	request.Push_Bool(out_link!=NULL || out_name!=NULL);
	request.Push_String(parentLink.c_str());
	request.Push_String(name.c_str());

	if (!SendPacketWait(request, response))
		return ETYPE_ERROR;

	uint8_t ret = 0;
	response.Get_U8(0, ret);
	if (out_link!=NULL)
		*out_link = response.GetString(1);
	if (out_name!=NULL)
		*out_name = response.GetString(2);
	return (EType)ret;
}

void ServerStorageProtocol::OnStorageAuthorization(const NetworkPacket &request)
{
    FUNCTION_TRACK
    string storageName = request.GetString(0);
    string password = request.GetString(1);

    this->connectedStorageId = g_db->StorageAuth(storageName, password);

    NetworkPacket response(request, CSNetworkLib::PACKET_SERVER_AuthStorageResp);

    if((1 > this->connectedStorageId) || (ConnectionManager::getInstance().getStorageConnection(this->connectedStorageId) != NULL) )
    {
        response.Push_S32(0);
        WARN("Storage not connected - %s (%d)", storageName.c_str(), this->connectedStorageId);
    }
    else
    {
        response.Push_S32(this->connectedStorageId);
		ConnectionManager::getInstance().PutStorage(this->connectedStorageId, this);
		RemoveHandler((int32_t) CSNetworkLib::PACKET_SERVER_AuthStorageReq);
		AddHandler<ServerStorageProtocol > ((int32_t) CSNetworkLib::PACKET_SERVER_OnSyncFileInfo, & ServerStorageProtocol::OnFileInfo);
		AddHandler<ServerStorageProtocol > ((int32_t) CSNetworkLib::PACKET_SERVER_OnSyncFolderInfo, & ServerStorageProtocol::OnFolderInfo);
		DBUG("Storage connected - %s (%d)", storageName.c_str(), this->connectedStorageId);
    }
    this->SendPacket(response);
}

void ServerStorageProtocol::OnFileInfo(const NetworkPacket &request)
{
    FUNCTION_TRACK
	std::string link(request.GetString(0));
	if (request.GetCount()>1)
	{
		std::string parentLink(request.GetString(1));
		std::string name(request.GetString(2));
		int64_t size = 0;
		uint64_t timestamp = 0;
		request.Get_S64(3, size);
		request.Get_U64(4, timestamp);

		g_db->StorageFileUpdate(link, parentLink, name, size, timestamp, connectedStorageId);
	}
	else
	{
		g_db->StorageFileRemove(link, connectedStorageId);
	}
}

void ServerStorageProtocol::OnFolderInfo(const NetworkPacket &request)
{
    FUNCTION_TRACK
	std::string link(request.GetString(0));
	if (request.GetCount()>1)
	{
		std::string parentLink(request.GetString(1));
		std::string name(request.GetString(2));
		bool sync = false;
		request.Get_Bool(3, sync);

		g_db->StorageFolderUpdate(link, parentLink, name, sync, connectedStorageId);
	}
	else
	{
		g_db->StorageFolderRemove(link, connectedStorageId);
	}
}

